package cn.itcast.hotel.service.impl;

import cn.itcast.hotel.mapper.HotelMapper;
import cn.itcast.hotel.pojo.Hotel;
import cn.itcast.hotel.pojo.HotelDoc;
import cn.itcast.hotel.pojo.PageResult;
import cn.itcast.hotel.pojo.RequestParams;
import cn.itcast.hotel.service.IHotelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {

    @Resource
    private RestHighLevelClient client;
    /**
     * 根据关键字搜索酒店信息
     * @param params 请求参数对象，包含用户输入的关键字
     * @return 酒店文档列表
     */
    @Override
    public PageResult search(RequestParams params) {
        try {
            // 1.准备Request
            SearchRequest request = new SearchRequest("hotel");
            // 2.准备DSL
            // 2.1.query
            // 1.准备Boolean查询
            buildBasicQuery(params,request);
            //2.2 分页
            int page = params.getPage();
            int size = params.getSize();

            request.source().from((page-1)*size).size(size);

            //发送请求
            SearchResponse response = client.search(request, RequestOptions.DEFAULT);
            //解析响应
            return handleResponse(response);
        }catch (IOException e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 因为条件构建的逻辑比较复杂，这里先封装为一个函数
     */
    public void buildBasicQuery(RequestParams params,SearchRequest request){
        //1.构建booleanQuery
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //2.关键词搜索
        String key = params.getKey();
        if(StringUtils.isEmpty(key)){
            boolQuery.must(
                    QueryBuilders.matchAllQuery()
            );
        }else {
            boolQuery.must(
                    QueryBuilders.matchQuery("all",key)
            );
        }
        //3.城市条件
        if(StringUtils.isNotBlank(params.getCity() )){
            boolQuery.filter(
                    QueryBuilders.termQuery("city",params.getCity())
            );
        }
        //4.品牌
        if(StringUtils.isNotBlank(params.getBrand())){
            boolQuery.filter(
                    QueryBuilders.termQuery("brand",params.getBrand())
            );
        }
        //4.星级条件
        if(StringUtils.isNotBlank(params.getStarName())){
            boolQuery.filter(
                    QueryBuilders.termQuery("starName",params.getStarName())
            );
        }
        //6.价格
        Integer minPrice = params.getMinPrice();
        Integer maxPrice = params.getMaxPrice();
        if(minPrice!=null && maxPrice!=null){
            maxPrice = maxPrice == 0 ? Integer.MAX_VALUE : maxPrice;
            boolQuery.filter(
                    QueryBuilders
                            .rangeQuery("price")
                            .gte(minPrice)
                            .lte(maxPrice)
            );
        }
        request.source().query(boolQuery);
        //高亮
        request.source().highlighter(
                new HighlightBuilder().field("name").requireFieldMatch(false)
        );
    }


    /**
     * 解析响应
     * @param response
     * @return
     */
    private PageResult handleResponse(SearchResponse response) {
        SearchHits searchHits = response.getHits();
        //获取总条数
        long total =  searchHits.getTotalHits().value;
        //文档数组
        SearchHit[] hits = searchHits.getHits();
        //遍历
        List<HotelDoc> hotelDocs = new ArrayList<>(hits.length);
        for (SearchHit hit : hits) {
            String json = hit.getSourceAsString();
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            // 4.6.处理高亮结果
            // 1)获取高亮map
            Map<String, HighlightField> map = hit.getHighlightFields();
            if(map!=null && !map.isEmpty()){
                //2)根据字段名 获取高亮结果
                HighlightField highlightField = map.get("name");
                if(highlightField!=null){
                    // 3）获取高亮结果字符串数组中的第1个元素
                    String hName = highlightField.getFragments()[0].toString();
                    // 4）把高亮结果放到HotelDoc中
                    hotelDoc.setName(hName);
                }
            }
            //5. 排序信息
//            Object[] sortValues = hit.getSortValues();
//            if (sortValues.length>0){
//                hotelDoc.setDis
//            }
            hotelDocs.add(hotelDoc);
        }
        return new PageResult(total,hotelDocs);
    }
}
